package com.virtualperson.service.impl;

import com.jcraft.jsch.*;
import com.virtualperson.service.ObjectStorageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Properties;
import java.util.UUID;

@Slf4j
@Service
public class AliyunServerStorageServiceImpl implements ObjectStorageService {

    @Value("${app.storage.server.host}")
    private String serverHost;

    @Value("${app.storage.server.port:22}")
    private int serverPort;

    @Value("${app.storage.server.username}")
    private String username;

    @Value("${app.storage.server.password}")
    private String password;

    @Value("${app.storage.server.private-key-path:}")
    private String privateKeyPath;

    @Value("${app.storage.server.remote-path:/var/www/uploads}")
    private String remotePath;

    @Value("${app.storage.server.base-url}")
    private String baseUrl;

    @Value("${app.storage.server.connection-timeout:30000}")
    private int connectionTimeout;

    @Value("${app.storage.server.session-timeout:30000}")
    private int sessionTimeout;

    @Override
    public String uploadFile(File file) {
        Session session = null;
        ChannelSftp channelSftp = null;
        
        try {
            // 创建JSch对象
            JSch jsch = new JSch();
            
            // 设置认证方式
            if (privateKeyPath != null && !privateKeyPath.trim().isEmpty()) {
                // 使用私钥认证
                jsch.addIdentity(privateKeyPath);
                log.info("使用私钥认证连接到服务器: {}", serverHost);
            } else {
                // 使用密码认证
                log.info("使用密码认证连接到服务器: {}", serverHost);
            }
            
            // 创建会话
            session = jsch.getSession(username, serverHost, serverPort);
            
            // 设置连接参数
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.setTimeout(connectionTimeout);
            
            // 如果使用密码认证，设置密码
            if (privateKeyPath == null || privateKeyPath.trim().isEmpty()) {
                session.setPassword(password);
            }
            
            // 连接服务器
            log.info("正在连接到服务器: {}:{}", serverHost, serverPort);
            session.connect();
            log.info("服务器连接成功");
            
            // 打开SFTP通道
            Channel channel = session.openChannel("sftp");
            channel.connect(sessionTimeout);
            channelSftp = (ChannelSftp) channel;
            log.info("SFTP通道建立成功");
            
            // 判断文件类型，决定存储目录
            String lowerName = file.getName().toLowerCase();
            String subDir;
            if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg") || lowerName.endsWith(".png") || lowerName.endsWith(".bmp") || lowerName.endsWith(".webp")) {
                subDir = "/picture";
            } else if (lowerName.endsWith(".mp3") || lowerName.endsWith(".wav") || lowerName.endsWith(".ogg") || lowerName.endsWith(".aac")) {
                subDir = "/audio";
            } else {
                subDir = ""; // 其他文件类型直接放根目录
            }

            // 生成远程文件路径
            String remoteFilePath = generateRemoteFilePath(file.getName(), subDir);
            String remoteDir = remoteFilePath.substring(0, remoteFilePath.lastIndexOf('/'));
            createRemoteDirectories(channelSftp, remoteDir); // 只创建父目录
            
            // 上传文件
            log.info("开始上传文件: {} -> {}", file.getAbsolutePath(), remoteFilePath);
            try (InputStream inputStream = new FileInputStream(file)) {
                channelSftp.put(inputStream, remoteFilePath);
            }
            log.info("文件上传成功: {}", remoteFilePath);
            
            // 生成访问URL
            String fileUrl = generateFileUrl(remoteFilePath);
            log.info("文件访问URL: {}", fileUrl);
            
            return fileUrl;
            
        } catch (Exception e) {
            log.error("文件上传到服务器失败: {}", file.getAbsolutePath(), e);
            throw new RuntimeException("文件上传到服务器失败: " + e.getMessage());
        } finally {
            // 关闭连接
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    }

    @Override
    public void deleteFile(String fileUrl) {
        Session session = null;
        ChannelSftp channelSftp = null;
        
        try {
            // 从URL中提取远程文件路径
            String remoteFilePath = extractRemotePathFromUrl(fileUrl);
            
            // 创建JSch对象
            JSch jsch = new JSch();
            
            // 设置认证方式
            if (privateKeyPath != null && !privateKeyPath.trim().isEmpty()) {
                jsch.addIdentity(privateKeyPath);
            }
            
            // 创建会话
            session = jsch.getSession(username, serverHost, serverPort);
            
            // 设置连接参数
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.setTimeout(connectionTimeout);
            
            // 如果使用密码认证，设置密码
            if (privateKeyPath == null || privateKeyPath.trim().isEmpty()) {
                session.setPassword(password);
            }
            
            // 连接服务器
            session.connect();
            
            // 打开SFTP通道
            Channel channel = session.openChannel("sftp");
            channel.connect(sessionTimeout);
            channelSftp = (ChannelSftp) channel;
            
            // 删除文件
            channelSftp.rm(remoteFilePath);
            log.info("远程文件删除成功: {}", remoteFilePath);
            
        } catch (Exception e) {
            log.error("删除远程文件失败: {}", fileUrl, e);
            throw new RuntimeException("删除远程文件失败: " + e.getMessage());
        } finally {
            // 关闭连接
            if (channelSftp != null && channelSftp.isConnected()) {
                channelSftp.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
    }

    @Override
    public String getFileUrl(String fileKey) {
        return baseUrl + "/" + fileKey;
    }

    /**
     * 生成远程文件路径，支持子目录
     */
    private String generateRemoteFilePath(String originalFileName, String subDir) {
        LocalDateTime now = LocalDateTime.now();
        String dateStr = now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        String timeStr = now.format(DateTimeFormatter.ofPattern("HHmmss"));
        String uuid = UUID.randomUUID().toString().substring(0, 8);
        
        // 获取文件扩展名
        String extension = "";
        if (originalFileName.contains(".")) {
            extension = originalFileName.substring(originalFileName.lastIndexOf('.'));
        }
        
        String fileName = String.format("%s_%s%s", timeStr, uuid, extension);
        // 拼接子目录
        String base = remotePath.endsWith("/") ? remotePath.substring(0, remotePath.length() - 1) : remotePath;
        String sub = (subDir != null && !subDir.isEmpty()) ? subDir : "";
        return base + sub + "/" + dateStr + "/" + fileName;
    }

    /**
     * 只创建目录，不带文件名
     */
    private void createRemoteDirectories(ChannelSftp channelSftp, String remoteDir) throws SftpException {
        String[] pathParts = remoteDir.split("/");
        StringBuilder currentPath = new StringBuilder();
        
        for (String part : pathParts) {
            if (part.isEmpty()) continue;
            
            currentPath.append("/").append(part);
            String path = currentPath.toString();
            
            try {
                // 尝试进入目录，如果失败则创建
                channelSftp.cd(path);
            } catch (SftpException e) {
                if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                    // 目录不存在，创建它
                    channelSftp.mkdir(path);
                    log.debug("创建远程目录: {}", path);
                } else {
                    throw e;
                }
            }
        }
    }

    /**
     * 生成文件访问URL
     */
    private String generateFileUrl(String remoteFilePath) {
        // 从远程路径中提取相对路径
        String relativePath = remoteFilePath.replace(remotePath, "").replaceFirst("^/", "");
        return baseUrl + "/" + relativePath;
    }

    /**
     * 从URL中提取远程文件路径
     */
    private String extractRemotePathFromUrl(String fileUrl) {
        String relativePath = fileUrl.replace(baseUrl + "/", "");
        return remotePath + "/" + relativePath;
    }
} 